#pragma once
#include "Sock.hpp"
#include "Log.hpp"
#include "Epoll.hpp"
#include "Protocol.hpp"
#include <iostream>
#include <unordered_map>
#include <string>
#include <functional>
#include <cstring>

class Connection;
class tcpServer;
using func_t = std::function<void(Connection *)>;
using callback = std::function<void(Connection*,std::string &request)>;
class Connection
{
public:
    Connection(int sock = -1) : _sock(sock), _tsvr(nullptr)
    {
    }
    void Callback(func_t recv_cb, func_t send_cb, func_t except_cb)
    {
        _recv_cb = recv_cb;
        _send_cb = send_cb;
        _except_cb = except_cb;
    }
    ~Connection()
    {

    }

public:
    int _sock;
    std::string _inbuffer;
    std::string _outbuffer;
    func_t _recv_cb;
    func_t _send_cb;
    func_t _except_cb;
    tcpServer* _tsvr;
};

class tcpServer
{
    const static int grnum = 64;
    const static uint16_t gport = 8080;
public:
    tcpServer(int port = gport) : _port(port), _revs_num(grnum)
    {
        // 1.创建listensock
        _listensock = Sock::Socket();
        Sock::Bind(_listensock, _port);
        Sock::Listen(_listensock);
        // 2.创建多路转接对象
        _poll.CreatEpoll();
        // 3.添加listensock到服务器中
        AddConnection(_listensock, std::bind(&tcpServer::Accepter, this, std::placeholders::_1), nullptr, nullptr);
        // 4.创建一个获取就绪事件缓冲区
        _revs = new struct epoll_event[_revs_num];
        logMessage(DEBUG, "listensock init success");
    }
    ~tcpServer()
    {
        if (_listensock >= 0)
        {
            close(_listensock);
        }
        if(_revs)
            delete[] _revs;
    }
    void AddConnection(int sock, func_t recv_cb, func_t send_cb, func_t except_cb)
    {
        Sock::SetNonBlock(sock);
        // 除了_listensock,未来我们会存在大量的socket，每一个sock都必须被封装成为一个Connection
        //    当服务器中存在大量的Connection的时候，TcpServer就需要将所有的Connection要进行管理：先描述，在组织
        // 1. 构建conn对象，封装sock
        Connection *con = new Connection(sock);
        con->_sock = sock;
        con->_tsvr = this;
        con->Callback(recv_cb, send_cb, except_cb);
        // 2. 添加sock到epoll中
        _poll.AddSockToEpoll(sock, EPOLLET | EPOLLIN);
        // 3. 还要将对应的Connection*对象指针添加到Connections映射表中！
        _connections.insert(std::make_pair(sock, con));
    }
    void Dispatch(callback cb)
    {
        _cb = cb;
        while (true)
        {
            Looponce();
        }
    }
    void Accepter(Connection *con)
    {
        logMessage(DEBUG, "accept been called");
        while (true)
        {
            std::string clientip;
            uint16_t clientport;
            int accpet_errno;
            int sock = Sock::Accept(_listensock, &clientip, &clientport, &accpet_errno);
            if (sock < 0)
            {
                if (accpet_errno == EAGAIN || accpet_errno == EWOULDBLOCK)
                    break;
                else if (errno == EINTR)
                    continue;
                else
                {
                    logMessage(WARNING, "accept sock error : %d %s", errno, strerror(errno));
                    break;
                }
            }
            if (sock >= 0)
            {
                AddConnection(sock, std::bind(&tcpServer::Recver, this, std::placeholders::_1),
                              std::bind(&tcpServer::Sender, this, std::placeholders::_1),
                              std::bind(&tcpServer::Excepter, this, std::placeholders::_1));
                logMessage(DEBUG, "accept new client %s:%d success,new sock : %d", clientip.c_str(), clientport, sock);
            }
        }
    }
    void Recver(Connection *con)
    {
        int err = false;
        while (true)
        {
            char buffer[1024];

            int n = recv(con->_sock, buffer, sizeof(buffer) - 1, 0);
            if (n < 0)
            {
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                    break;
                else if (errno == EINTR)
                    continue;
                else
                {
                    logMessage(WARNING, "recv errno %d : %s", errno, strerror(errno));
                    con->_except_cb(con);
                    err = true;
                    break;
                }
            }
            else if (n == 0)
            {
                logMessage(DEBUG, "client[%d] quit,server close %d", con->_sock, con->_sock);
                // close(con->_sock);
                // _connections.erase(con->_sock);
                con->_except_cb(con);
                err = true;
                break;
            }
            else
            {
                buffer[n] = 0;
                con->_inbuffer += buffer;
            }
            //logMessage(DEBUG,"recv message:%s",con->_inbuffer.c_str());
        } // while end
        logMessage(DEBUG, "con->_inbuffer[sock: %d]: %s", con->_sock, con->_inbuffer.c_str());
        if (!err)
        {
            std::vector<std::string> messgaes;
            SplitMessage(con->_inbuffer,&messgaes);
            for(auto& msg : messgaes) _cb(con,msg);
            // 此时信息已经全部在inbuffer
        }
    }
    void Sender(Connection *con)
    {
        while (true)
        {
            ssize_t n = send(con->_sock, con->_outbuffer.c_str(), con->_outbuffer.size(), 0);
            if (n > 0)
            {
                con->_outbuffer.erase(0,n);
                if(con->_outbuffer.empty()) break;
            }
            else
            {
                if (errno == EAGAIN && errno == EWOULDBLOCK)
                    break;
                else if (errno == EINTR)
                    continue;
                else
                {
                    logMessage(DEBUG, "sock %d send error %d %s", con->_sock, errno, strerror(errno));
                    con->_except_cb(con);
                    break;
                }
            }
        }
        // 发完了吗？不确定，但是我们保证，如果没有出错，一定是要么发完，要么发送条件不满足，下次发送
        if(con->_outbuffer.empty()) EnableReadWrite(con,true,false);
        else EnableReadWrite(con,true,true);
    }
    void Excepter(Connection *con)
    {
        if(!ConnectionIsExist(con->_sock)) return;
        // 1.从epoll中移除
        _poll.DelFromEpoll(con->_sock);
        // 2.从unordered_map中移除
        _connections.erase(con->_sock);
        // 3.关闭文件描述符
        close(con->_sock);
        // 4.delete con
        delete con;
        logMessage(DEBUG,"excepter 回收所有的异常情况");
    }
    void EnableReadWrite(Connection* con,bool readable,bool writeable)
    {
        uint16_t event = (readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0);
        bool res = _poll.CtlPoll(con->_sock,event);
        if(!res)
        {
            logMessage(DEBUG,"enable error %d : %s",errno,strerror(errno));
        }
    }
    void Looponce()
    {
        int n = _poll.WaitPoll(_revs, _revs_num);
        for (int i = 0; i < n; i++)
        {
            int sock = _revs->data.fd;
            uint16_t revent = _revs->events;
            if (revent & EPOLLIN)
            {
                if (ConnectionIsExist(sock) && _connections[sock]->_recv_cb)
                {
                    _connections[sock]->_recv_cb(_connections[sock]);
                }
            }
            if (revent & EPOLLOUT)
            {
                if (ConnectionIsExist(sock) && _connections[sock]->_send_cb)
                {
                    _connections[sock]->_send_cb(_connections[sock]);
                }
            }
        }
    }
    bool ConnectionIsExist(int sock)
    {
        auto iter = _connections.find(sock);
        if (iter == _connections.end())
            return false;
        else
            return true;
    }

private:
    int _listensock;
    uint16_t _port;
    Epoll _poll;
    // sock :connection
    struct epoll_event *_revs;
    int _revs_num;
    std::unordered_map<int, Connection *> _connections;


    callback _cb;
};